class Compiler {
  constructor(vm) {
    this.vm = vm
    this.el = vm.$el

    this.compile(this.el)
  }

  // 分析el
  compile(el) {
    let nodeList = Array.from(el.childNodes)
    nodeList.forEach(node => {
      /**
       * 处理文本节点和元素节点
       */
      if (this.isTextNode(node) && /\S/.test(node.textContent)) {
        this.textCompile(node)
      } else if (this.isElementNode(node)) {
        this.elementCompile(node)
      }
      
      // 如果节点下面还有子节点，继续遍历
      if (node.childNodes && node.childNodes.length) this.compile(node)

    })
  }

  textCompile(node) {
    // console.dir(node);
    // 如果符合{{ xx }}的格式，要将data中的值赋值到textNode上
    let reg = /\{\{(.+?)\}\}/
    if (reg.test(node.textContent)) {
      let key = RegExp.$1.trim()
      // console.log(key);
      node.textContent = tools.getChainValue(this.vm, key)

      new Watcher(this.vm, key, (newValue) => {
        node.textContent = newValue
      })
    }
  }

  elementCompile(node) {
    Array.from(node.attributes).forEach(attr => {
      let attrName = attr.name
      let key = attr.value
      if (this.isDirective(attrName)) {
        attrName = attrName.substr(2)
        // console.log(attrName, ": ", key);
        this.updater(node, key, attrName)
      }
    })
  }

  updater(node, key, attrName) {
    let updaterFn = null
    if (this.isOnDirective(attrName)) {
      updaterFn = this['on' + 'Updater']
    } else {
      updaterFn = this[attrName + 'Updater']
    }
    updaterFn.call(this, node, tools.getChainValue(this.vm, key), key)
  }

  textUpdater(node, value, key) {
    node.textContent = value
    // 因为每种watcher的cb不一样，所以需要在每个updater方法中都声明一个watcher
    new Watcher(this.vm, key, (newValue)=> {
      node.textContent = newValue
    })
  }

  modelUpdater(node, value, key) {
    node.value = value
    new Watcher(this.vm, key, (newValue)=> {
      node.value = newValue
    })

    // 添加input事件
    node.addEventListener("input", () => {
      // this.vm[key] = node.value
      tools.setChainValue(this.vm, key, node.value)
    })
  }

  htmlUpdater(node, value, key) {
    node.innerHTML = value

    new Watcher(this.vm, key, (newValue)=> {
      node.innerHTML = value
    })
  }

  onUpdater(node, value, key) {
    console.log(value);
    node.addEventListener('click', value)
  }

  isDirective(attrName) {
    return attrName.startsWith("v-")
  }

  isTextNode(node) {
    return node.nodeType === 3
  }

  isElementNode(node) {
    return node.nodeType === 1
  }

  // 判断指令是够是一个 v-on 指令
  isOnDirective (attrName) {
    return attrName.startsWith('on:')
  }
}